package csharp.cauth;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;

import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Priority;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.config.Configuration;

import com.alta189.sqlLibrary.MySQL.mysqlCore;
import com.nijiko.permissions.PermissionHandler;
import com.nijikokun.bukkit.Permissions.Permissions;

import csharp.cauth.commands.CACAuth;
import csharp.cauth.commands.CALogin;
import csharp.cauth.commands.CARegister;
import csharp.cauth.commands.CASetPassword;
import csharp.cauth.listeners.CABlockListener;
import csharp.cauth.listeners.CAEntityListener;
import csharp.cauth.listeners.CAPlayerListener;
import csharp.cauth.listeners.CAWorldListener;
import csharp.cauth.properties.InventoryProp;
import csharp.cauth.properties.PlayerProp;
import csharp.cauth.utils.Log;

/**
 * @author Ярослав (CSharp) Main class.
 */
public class CAuth extends JavaPlugin
{
	/**
	 * Listeners.
	 */
	private final CAPlayerListener playerListener = new CAPlayerListener(this);
	private final CABlockListener blockListener = new CABlockListener(this);
	private final CAEntityListener entityListener = new CAEntityListener(this);
	private final CAWorldListener worldListener = new CAWorldListener(this);

	/**
	 * Properties.
	 */
	public static String mainDir = "plugins/CAuth";
	private static File propFile = new File(mainDir + File.separator
			+ "config.yml");
	private static File langFile;
	// public static Properties props = new Properties();
	public static Configuration configuration = new Configuration(propFile);
	public static Configuration language;

	/**
	 * "Auth" lists.
	 */
	public static ArrayList<PlayerProp> players = new ArrayList<PlayerProp>(); // Players
																				// to
																				// load/store
																				// into
																				// file.
	public static HashMap<String, Integer> ipCounter = new HashMap<String, Integer>(); // For
																						// IP
																						// registration
																						// checking.
																						// Executing
																						// once
																						// at
																						// plugin
																						// start.
	public static ArrayList<Player> authorized = new ArrayList<Player>(); // Authorized
																			// players.
	public static HashMap<Player, InventoryProp> unauthorized = new HashMap<Player, InventoryProp>(); // Unauthorized
																										// players.
																										// Used
																										// for
																										// store
																										// inventory.
	public static HashMap<Player, Integer> wrongEnters = new HashMap<Player, Integer>();

	/**
	 * Plugins instance.
	 */
	public static CAuth instance;
	public static PermissionHandler permissionHandler;
	public static PluginDescriptionFile pluginDesc;
	public static mysqlCore manageMySQL;

	@Override
	public void onDisable()
	{
		Log.log(Level.INFO, "Updating players locations.");

		for (PlayerProp prop : players)
		{
			Player player = null;
			player = getServer().getPlayer(prop.getLogin());

			if (player != null)
			{
				prop.setLastLoc(player.getLocation());
			}
		}

		PlayersSL.savePlayers();

		Log.log(Level.INFO, "Plugin unloaded.");
	}

	@Override
	public void onEnable()
	{
		// Set instance.
		instance = this;
		pluginDesc = this.getDescription();

		// Make plugin directory if not exists.
		new File(mainDir).mkdir();

		// Loading configuration from file.
		loadConfiguration();

		if (PluginConfig.useMySQL)
		{
			manageMySQL = new mysqlCore(Log.logger, "[CAuth] ",
					PluginConfig.mysqlHost, PluginConfig.mysqlDB,
					PluginConfig.mysqlUser, PluginConfig.mysqlPassword);

			manageMySQL.initialize();

			try
			{
				if (manageMySQL.checkConnection())
				{
					if (!manageMySQL.checkTable("users"))
					{
						manageMySQL
								.createTable("CREATE TABLE `users` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`login` varchar(32) NOT NULL,`password` varchar(32) NOT NULL,`ip` varchar(32) NOT NULL,`x` double DEFAULT NULL,`y` double DEFAULT NULL,`z` double DEFAULT NULL,`world` varchar(64) DEFAULT NULL,`registered` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,`lastlogin` timestamp NULL DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8");
					}
				}
				else
				{
					PluginConfig.useMySQL = false;
				}
			}
			catch (MalformedURLException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			catch (InstantiationException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			catch (IllegalAccessException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		// Loading players from file.
		PlayersSL.loadPlayers();

		if (PluginConfig.usePermissions)
			loadPermissions();

		Player[] playersOnline = getServer().getOnlinePlayers();

		for (final Player p : playersOnline)
		{
			PlayerInventory inventory = p.getInventory();

			CAuth.unauthorized.put(p, new InventoryProp(inventory));

			Integer taskId = getServer().getScheduler()
					.scheduleAsyncDelayedTask(this, new Runnable()
					{
						@Override
						public void run()
						{
							playerListener.tasks.remove(p);

							if (!CAuth.authorized.contains(p))
							{
								p.kickPlayer("[CAuth] "
										+ Language.YOU_NEED_AUTHORIZE_TO_PLAY);
							}
						}
					}, PluginConfig.kickPlayerAfter * 10);

			playerListener.tasks.put(p, taskId);

			inventory.clear();
			inventory.setBoots(null);
			inventory.setChestplate(null);
			inventory.setHelmet(null);
			inventory.setLeggings(null);
		}

		// Registering events.
		registerEvents();

		// Registering commands.
		registerCommads();

		// Plugin started!
		Log.log(Level.INFO, "Plugin loaded.");
		Log.log(Level.INFO, "Version: " + pluginDesc.getVersion());
	}

	private void loadPermissions()
	{
		Plugin permissionsPlugin = getServer().getPluginManager().getPlugin(
				"Permissions");

		if (permissionHandler == null)
		{
			if (permissionsPlugin != null)
			{
				permissionHandler = ((Permissions) permissionsPlugin)
						.getHandler();
			}
			else
			{
				Log.log(Level.INFO,
						"No permissions plugin installed, default command executor selected.");

				PluginConfig.usePermissions = false;
			}
		}
	}

	/**
	 * Registering events in plugin manager.
	 */
	private void registerEvents()
	{
		PluginManager pm = getServer().getPluginManager();

		// Registering events.
		pm.registerEvent(Event.Type.PLAYER_JOIN, playerListener,
				Priority.Highest, this);
		pm.registerEvent(Event.Type.PLAYER_QUIT, playerListener,
				Priority.Highest, this);
		pm.registerEvent(Event.Type.PLAYER_MOVE, playerListener,
				Priority.Highest, this);
		pm.registerEvent(Event.Type.BLOCK_BREAK, blockListener,
				Priority.Highest, this);
		pm.registerEvent(Event.Type.PLAYER_COMMAND_PREPROCESS, playerListener,
				Priority.Highest, this);
		pm.registerEvent(Event.Type.PLAYER_CHAT, playerListener,
				Priority.Highest, this);
		pm.registerEvent(Event.Type.PLAYER_DROP_ITEM, playerListener,
				Priority.Highest, this);
		pm.registerEvent(Event.Type.PLAYER_PICKUP_ITEM, playerListener,
				Priority.Highest, this);
		pm.registerEvent(Event.Type.PLAYER_INTERACT, playerListener,
				Priority.Highest, this);
		pm.registerEvent(Event.Type.PLAYER_INTERACT_ENTITY, playerListener,
				Priority.Highest, this);
		pm.registerEvent(Event.Type.PLAYER_LOGIN, playerListener,
				Priority.Highest, this);
		pm.registerEvent(Event.Type.PLAYER_KICK, playerListener,
				Priority.Highest, this);
		pm.registerEvent(Event.Type.ENTITY_DAMAGE, entityListener,
				Priority.Highest, this);
		pm.registerEvent(Event.Type.ENTITY_TARGET, entityListener,
				Priority.Highest, this);
		pm.registerEvent(Event.Type.INVENTORY_OPEN, playerListener,
				Priority.Highest, this); // Need to fix it.
		pm.registerEvent(Event.Type.WORLD_SAVE, worldListener,
				Priority.Highest, this);
	}

	/**
	 * Registering commands.
	 */
	private void registerCommads()
	{
		getCommand("register").setExecutor(new CARegister(this));
		getCommand("login").setExecutor(new CALogin(this));
		getCommand("setpass").setExecutor(new CASetPassword(this));
		getCommand("cauth").setExecutor(new CACAuth(this));
	}

	/**
	 * Loading plugin configuration from file.
	 */
	public static void loadConfiguration()
	{
		if (!propFile.exists())
		{
			try
			{
				propFile.createNewFile();

				// configuration.load();

				configuration.setProperty("general.usePermissions", false);
				configuration.setProperty("general.useMySQL", false);
				configuration.setProperty("general.kickSameNicks", true);
				configuration.setProperty("general.language", "en");
				configuration.setProperty("players.kickPlayerAfter", 60);
				configuration.setProperty("players.accountsPerIP", 1);
				configuration.setProperty("players.wrongPasswordEnterCount", 5);
				configuration.setProperty("players.remember.rememberOperators",
						false);
				configuration.setProperty("players.remember.usePermissions",
						false);
				configuration.setProperty("players.remember.groups",
						new ArrayList<Object>());
				configuration.setProperty("mysql.host", "127.0.0.1");
				configuration.setProperty("mysql.db", "cauth");
				configuration.setProperty("mysql.user", "root");
				configuration.setProperty("mysql.password", "root");

				configuration.save();
				configuration.load();

				PluginConfig.extractVariables();
			}
			catch (IOException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else
		{
			configuration.load();

			PluginConfig.extractVariables();
		}

		PluginConfig.extractVariables();

		Log.log(Level.INFO, "Configuration loaded.");

		langFile = new File(mainDir + File.separator + "lang" + File.separator
				+ PluginConfig.language + ".yml");
		language = new Configuration(langFile);
		
		if (langFile.exists())
		{
			if (language != null)
			{
				language.load();
				
				Log.log(Level.INFO, "Loading language file.");

				Language.extractVariables();

				Log.log(Level.INFO, "Language file (" + langFile.getAbsolutePath() + ") loaded.");
				
				return;
			}
		}
		
		Log.log(Level.INFO, "No language file, using default (English).");
	}
}
